#pragma once
#include "common.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
#include "Thread.hpp"
#include <functional>
using namespace ThreadPoolModule;

const static int backlog = 8;

using task_t = std::function<void()>;

using func_t = std::function<std::string(const std::string,InetAddr&)>;

class TcpServer : public NOCOPY // 服务器是不允许拷贝和赋值的，将父类涉及成不能拷贝和赋值的模式，通过子类来继承
{
public:
    TcpServer(u_int16_t port, func_t fun)
        : _port(port)
        ,_func(fun)
    {
    }
    class ThreadData
    {
    public:
        ThreadData(int sockfd, InetAddr &addr, TcpServer *s)
            : _sockfd(sockfd), _addr(addr), _this(s)
        {
        }
        int _sockfd;
        InetAddr _addr;
        TcpServer *_this;
    };

    void service(int sockfd, InetAddr &peer)
    {
        while (true)
        {
            char buffer[1024];
            ssize_t n = read(sockfd, buffer, sizeof(buffer));
            if (n > 0)
            {
                buffer[n] = 0;
                //LOG(LogLevel::DEBUG) << peer.StringAddr() << " #: " << buffer;

                std::string line = buffer;
                std::string echo = _func(line,peer);

                write(sockfd, echo.c_str(), echo.size());
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << peer.StringAddr() << "退出了";
                close(sockfd);
                break;
            }
            else
            {
                LOG(LogLevel::DEBUG) << peer.StringAddr() << "异常";
                close(sockfd);
                break;
            }
        }
    }

    void Init()
    {
        // 1.创建套接字文件
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error";
            exit(SOCKET_ERROR);
        }
        LOG(LogLevel::INFO) << "socket success";

        // 2.bind
        // 将主机字节序转为网络字节序
        InetAddr local(_port);
        int n = bind(_listensockfd, local.NetAddrptr(), local.NetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(BIND_ERROR);
        }
        LOG(LogLevel::INFO) << "binb success";
        // 当前服务器任意ip + 端口号设置为监听，来接收客户端的数据
        n = listen(_listensockfd, backlog); // 将当前套接字置为监听状态  backlog 用于设置待处理链接队列中最大连接数，该文件描述符不做信息处理，之后交给accept返回的文件描述符处理
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen error";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success: " << _listensockfd; //
    }

    static void *Routine(void *t)
    {
        pthread_detach(pthread_self()); // 将当前线程分离，线程结束时，自动释放
        ThreadData *td = static_cast<ThreadData *>(t);
        td->_this->service(td->_sockfd, td->_addr);
        delete td;
        return nullptr;
    }

    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            struct sockaddr_in peer; // 服务器创建一个本地的sockadd_in 来接收客户端发送的ip和port
            socklen_t len = sizeof(sockaddr_in);
            // 阻塞等待远端服务器连接，等待客服端connect发起连接
            int sockfd = accept(_listensockfd, CONV(peer), &len); // 接收远端服务器发送的信息，用另一个文件描述符来接收
            if (sockfd < 0)
            {
                LOG(LogLevel::WARRING) << "accept error";
                continue;
            }
            // 网络字节序转主机
            InetAddr addr(peer); // Tcpserver只收消息，不处理消息，实例化另一个对象来处理

            // 1.version 多进程版本
            //  pid_t id = fork();
            //  if(id == 0)
            //  {
            //      close(_listensockfd);
            //      //子进程退出
            //      if(fork() > 0)
            //          exit(OK);
            //      //孙子进程去执行相应代码，孙子进程退出时，由1号进程接收
            //      service(sockfd, addr);
            //      exit(OK);
            //  }
            //  else if(id > 0)
            //  {
            //      close(sockfd);//父进程关闭不需要的接口
            //      pid_t rid = waitpid(id,nullptr,0);
            //      (void)rid;
            //  }

            // 2.多线程版本
            ThreadData *td = new ThreadData(sockfd, addr, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, Routine, td);
        
            //3.进程池
            // ThreadPool<task_t>::GetInstStance()->Equeue([this,sockfd,&addr](){
            //     this->service(sockfd,addr);
            // });
        }
    }

private:
    u_int16_t _port;
    int _listensockfd; // 功能只是用来
    bool _isrunning;
    func_t _func;
};